package com.itheima.reggie.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishDto;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/dish")
@Slf4j
public class DishController {

    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private RedisTemplate redisTemplate;

    //添加新菜品
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto){

        dishService.saveWithFlavor(dishDto);
        //更新缓存，将redis中存储的categoryId对应的菜品
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);
        return R.success("新增菜品成功");
    }

    //菜品分页查询
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){

        //构造分页查询构造器对象
        Page<Dish> pageInfo = new Page<>(page,pageSize);

        //由于菜品表里只有categoryId，而我们需要菜品分类名字，因此需要通过categoryId来查询菜品分类名
        // 设定返回的构造器对象，dishDto对象里有一个categoryName的属性，所以我们将返回这个对象
        Page<DishDto> dishDtoPage = new Page<>(page,pageSize);
        //构建条件构造器
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        lambdaQueryWrapper.like(name != null,Dish::getName, name);

        lambdaQueryWrapper.orderByDesc(Dish::getUpdateTime);

        //分页查询
        dishService.page(pageInfo, lambdaQueryWrapper);


        //对象拷贝，忽略records，即不拷贝records属性的值
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");

        //获得records
        List<Dish> records = pageInfo.getRecords();
        //通过stream流将records转换为DishDto类型的数据，因为里面有categoryName
        List<DishDto> list = records.stream().map((item) ->{
            DishDto dishDto = new DishDto();
            //item即代表records中的每一项dish
            //将item数据赋值到dishDto
            BeanUtils.copyProperties(item, dishDto);

            //获取CategoryId用来查询categoryName
            Long categoryId = item.getCategoryId();

            //查询
            Category category = categoryService.getById(categoryId);

            //这里有可能会出现categoryId查不到category的情况，因为这些菜品没有分类
            //所以要先判断，如果查到了category再查找categoryName
            if (category != null) {
                String categoryName = category.getName();
                //将dishDto的categoryName设置为这个值
                dishDto.setCategoryName(categoryName);
            }
            //返回dishDto对象
            return dishDto;
            //将stream流转换为list
        }).collect(Collectors.toList());

        //将新的List<DishDto>数据导入dishDtoPage
        dishDtoPage.setRecords(list);

        return R.success(dishDtoPage);

    }

    //回显要修改的菜品数据
    @GetMapping("/{id}")
    public R<DishDto> getById(@PathVariable Long id){
        //调用DishService中的getById方法来回显数据，
        // 但DishService封装的是Dish，并没有口味的列表，
        // 所以还是要重新写一个能把口味和其他数据一起查出来的函数
        //这里要在DishService里重新写一个返回DishDto对象的函数

        DishDto dishDto = dishService.getWithFlavor(id);
        return R.success(dishDto);
    }
    //修改菜品
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        //由于涉及到菜品口味的问题

        dishService.updateWithFlavor(dishDto);
        //更新缓存，将redis中存储的categoryId对应的菜品
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);

        return R.success("菜品修改成功");
    }

    //删除单个菜品或批量删除
    @DeleteMapping
    public R<String> delete(@RequestParam(value="ids") List<String> ids){
        //前端传入的ids有两种情况
        //第一种就是只有一个id，String类型，
        //第二种为多个id，也是String类型，里面的格式是id,id,id...
        //字符串参数id,id,id这种用,号隔开的，可以用List<String> ids这个列表进行接收，但需要加上@RequestParam
        //而只有一个id的ids，当然也可以用List<String> ids进行接收
//        System.out.println(ids);
//        String type = ids.getClass().getName();//打印变量的类型
//        System.out.println(type);
        dishService.deleteWithFlavor(ids);

        //更新缓存，将redis中存储的categoryId对应的菜品
        for(String id : ids){
            Dish dish = dishService.getById(id);
            String key = "dish_" + dish.getCategoryId() + "_1";
            redisTemplate.delete(key);
        }

        return R.success("删除成功");
    }

    //启售或停售，单个或多个
    @PostMapping("/status/{statusValue}")
    public R<String> updateStatus(@PathVariable Integer statusValue,@RequestParam List<String> ids){

        //这里使用updatewrapper，因为要设定修改哪个属性的值
        UpdateWrapper<Dish> wrapper = new UpdateWrapper<>();

        wrapper.set("status",statusValue).in("id",ids);

        dishService.update(null,wrapper);

        //更新缓存，将redis中存储的categoryId对应的菜品
        for(String id : ids){
            Dish dish = dishService.getById(id);
            String key = "dish_" + dish.getCategoryId() + "_1";
            redisTemplate.delete(key);
        }
        return R.success("修改状态成功");
    }

    //根据菜品id或菜品名称，查询对应的所有菜品
    //后端套餐添加菜品时使用
    //前端点餐时选择规格使用，index界面加载时使用
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        //先从redis中查询有没有这个菜品分类的对应的菜品信息
        //这里要存对象，要考虑redis中存什么数据类型
        List<DishDto> dishDtoList;
        ValueOperations valueOperations = redisTemplate.opsForValue();
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();
        dishDtoList = (List<DishDto>)valueOperations.get(key);
        //如果有，则直接返回
        if(dishDtoList != null){
            System.out.println("dishDtoList为：");
            System.out.println(dishDtoList);
            return R.success(dishDtoList);
        }

        //构造条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();

        //创建查询条件
        //如果CategoryId存在，则判断
        queryWrapper.eq(dish.getCategoryId() != null,Dish::getCategoryId,dish.getCategoryId());
        //如果name存在则判断
        queryWrapper.like(dish.getName() != null,Dish::getName,dish.getName());

        //只查状态为1的菜品（在售菜品）
        queryWrapper.eq(Dish::getStatus,1);
        //排序条件
        queryWrapper.orderByAsc(Dish::getCategoryId);

        List<Dish> list = dishService.list(queryWrapper);

        //下面的代码是前端点餐时选择规格使用要添加的，因此点餐时需要选择口味
        //因此需要返回菜品对应的口味，也就是要返回DishDto

        //下面进行封装
        dishDtoList = list.stream().map((item)->{
            DishDto dishDto = new DishDto();

            //把dish中的数据赋值到dishDto中
            BeanUtils.copyProperties(item,dishDto);
            //查询口味表，并封装到DishDto中

            //由于dish表中没有categoryName属性，只存了categoryId
            Long categoryId = item.getCategoryId();
            //所以我们要根据categoryId查询对应的category
            Category category = categoryService.getById(categoryId);

            //然后取出categoryName，赋值给dishDto
            if(category != null){
                dishDto.setCategoryName(category.getName());
            }

            //然后获取一下菜品id，根据菜品id去dishFlavor表中查询对应的口味，并赋值给dishDto
            Long dishId = item.getId();

            LambdaQueryWrapper<DishFlavor> qw = new LambdaQueryWrapper<>();

            qw.eq(dishId != null,DishFlavor::getDishId,dishId);

            List<DishFlavor> dishFlavorList = dishFlavorService.list(qw);

            dishDto.setFlavors(dishFlavorList);

            return dishDto;

        }).collect(Collectors.toList());

        //将查询的结果让redis缓存，设置存活时间为60分钟
        valueOperations.set(key,dishDtoList,60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

}
